package chanx

import (
	"unsafe"

	"github.com/gookit/color"
)

// runtime.hchan
type hchan struct {
	//channel分为无缓冲和有缓冲两种。
	//对于有缓冲的channel存储数据，借助的是如下循环数组的结构
	qcount   uint           // 循环数组中的元素数量
	dataqsiz uint           // 循环数组的长度
	buf      unsafe.Pointer // 指向底层循环数组的指针
	elemsize uint16         //能够收发元素的大小

	closed uint32 //channel是否关闭的标志
	//elemtype *abi.Type //channel中的元素类型

	//有缓冲channel内的缓冲数组会被作为一个“环型”来使用。
	//当下标超过数组容量后会回到第一个位置，所以需要有两个字段记录当前读和写的下标位置
	sendx uint // 下一次发送数据的下标位置
	recvx uint // 下一次读取数据的下标位置

	//当循环数组中没有数据时，收到了接收请求，那么接收数据的变量地址将会写入读等待队列
	//当循环数组中数据已满时，收到了发送请求，那么发送数据的变量地址将写入写等待队列
	//recvq    waitq  // 读等待队列
	//sendq    waitq  // 写等待队列

	//lock mutex //互斥锁，保证读写channel时不存在并发竞争问题
}

// G1 发送
func sendTask(taskList []any) {
	ch := make(chan any, 4) // 初始化长度为4的channel
	for _, task := range taskList {
		ch <- task //发送任务到channel
	}

}

// G2 接受
func handleTask(ch chan any) {
	for {
		task := <-ch                 //接收任务
		color.Redln("process", task) //处理任务
	}
}

//
//初始hchan结构体重的buf为空，sendx和recvx均为0。
//当G1向ch里发送数据时，首先会对buf加锁，然后将数据copy到buf中，然后sendx++，然后释放对buf的锁。
//当G2消费ch的时候，会首先对buf加锁，然后将buf中的数据copy到task变量对应的内存里，然后recvx++,并释放锁。

//底层是通过hchan结构体的buf，并使用copy内存的方式进行通信， Copy 可以防止数据在传输过程中被意外或恶意修改

//GPM
//【G】goroutine是Golang实现的用户空间的轻量级的线程
//【M】代表操作系统线程
//【P】处理器, 它包含了待运行goroutine。

/*

当Goroutine1 发送data
runtime并不会对hchan结构体题的buf进行加锁
	而是直接将G1里的发送到ch的数据copy到了G2 sudog里对应的elem指向的内存地址！【不通过buf】
*/

//当Goroutine1 data -> buf已满的ch （阻塞）
//						通知调度器，调度器会将G1的状态设置为waiting, 并移除与线程M的联系
//						然后从P的runqueue中选择一个goroutine在线程M中执行
//						此时G1就是阻塞状态，但是不是操作系统的线程阻塞，所以这个时候只用消耗少量的资源。

/*

当G1变为waiting状态后，会创建一个代表自己的sudog的结构，然后放到sendq这个list中
sudog结构中保存了channel相关的变量的指针
(如果该Goroutine是sender，那么保存的是待发送数据的变量的地址，如果是receiver则为接收数据的变量的地址
之所以是地址，前面我们提到在传输数据的时候使用的是copy的方式)


*/
//当Goroutine2 data <- buf已满的ch （解除G1的阻塞）
//						会通知调度器，设置G1的状态为runnable
//						将加入P的runqueue里，等待线程执行.
